//
//  ContentView.swift
//  Maze24
//
//  Created by Mars on 2020/10/17.
//

import SwiftUI
import AVFoundation

enum ActiveSheet: Identifiable {
  case answer
  case customGame
  case congratulation
  
  var id: Int {
    hashValue
  }
}

struct ContentView: View {
  @ObservedObject var model: Model = Model()
  @Environment(\.colorScheme) var colorScheme: ColorScheme
  
  @State var currentNumberIdx: Int = -1
  @State var currentOpIdx: Int = -1
  @State var attempts: Int = 0
  
  @State var player: AVAudioPlayer!
  @State var feedback = UINotificationFeedbackGenerator()
  
  /// 1 - answer
  /// 2 - new
  /// 3 - congratulation
  @State var activeSheet: ActiveSheet?
  @State var ifPresentSheet = false
  
  let errSound = URL(fileURLWithPath: Bundle.main.path(forResource: "error.wav", ofType: nil)!)
  let opSound = URL(fileURLWithPath: Bundle.main.path(forResource: "op.mp3", ofType: nil)!)
  let clickSound = URL(fileURLWithPath: Bundle.main.path(forResource: "click.wav", ofType: nil)!)
  let clearnaceSound = URL(fileURLWithPath: Bundle.main.path(forResource: "success.wav", ofType: nil)!)
  
  var body: some View {
    GeometryReader { proxy in
      NavigationView {
        ZStack {
          // Background
          Color("MainBg")
          
          // Content view
          VStack {
            buildHelpButton()
              .padding(.bottom, 32)
            
            buildBigNumButtons(from: model.buttons, size: proxy.size)
              .padding(.bottom, 32)
            
            buildOperations(from: model.ops)
            
            Spacer()
            
            buildSettings(size: proxy.size)
              .padding(.bottom, 50)
          }
        }
        .navigationTitle("Maze 24")
        .navigationBarTitleDisplayMode(.inline)
        .toolbar {
          ToolbarItem(placement: .navigationBarTrailing) {
            NavigationLink(destination: Settings(model: model)) {
              Image(systemName: "gearshape.fill")
            }
          }
        }
        .ignoresSafeArea(edges: .bottom)
      }
      .sheet(item: $activeSheet) { item in
        switch item {
        case ActiveSheet.answer:
          AnswerView(answer: model.buildAnswer())
        case ActiveSheet.customGame:
          CustomView(model: model)
        case ActiveSheet.congratulation:
          Congratulation(archievement: model.archievement)
        }
      }
      .accentColor(.purple)
      
      // End NavigationView
    }
  }
  
  func buildHelpButton() -> some View {
    return HStack {
      Spacer()
      
      Button(action: {
        let url = URL(string: "https://apps.apple.com/us/app/%E6%99%BA%E8%B6%A3-24-%E7%82%B9/id1548929357")!
        let prompt = "Hi，能用 \(model.question[0]), \(model.question[1]), \(model.question[2]), \(model.question[3]) 和 +, -, ×, ÷ 帮我算下 24 点嘛，拜托啦～"
        let av = UIActivityViewController(activityItems: [prompt, url], applicationActivities: nil)
        UIApplication.shared.windows.first?.rootViewController?.present(av, animated: true, completion: nil)
      }, label: {
        VStack(spacing: 5) {
          Image(systemName: "questionmark.diamond.fill")
            .font(.title)
          Text("获得帮助")
            .font(.footnote)
        }
        .foregroundColor(.primary)
      })
    }
    .padding([.top, .trailing], 30)
  }
  
  func buildBigNumButton(from item: ButtonItem, size: CGSize, corners: UIRectCorner) -> some View {
    Button(action: {
      if item.category != .empty {
        model.apply(item: item)
        
        player = try! AVAudioPlayer(contentsOf: clickSound)
        player.play()
        
        if model.isClearance {
          activeSheet = ActiveSheet.congratulation
          ifPresentSheet = true
          
          player = try! AVAudioPlayer(contentsOf: clearnaceSound)
          player.play()
        }
      }
    }, label: {
      Text(item.title)
    })
    .buttonStyle(BigNumButtonStyle(cornerRadius: 20, corners: corners))
    .frame(width: size.width, height: size.height)
    .overlay(
      RoundedCorners(cornerRadius: 20, corners: corners)
        .stroke(Color.blue, lineWidth: 4)
        .opacity(item.index == model.currentNumBtnIndex ? 1 : 0)
    )
    .disabled(item.category == .empty)
  }
  
  func buildBigNumButtons(from btns: [ButtonItem], size: CGSize) -> some View {
    let btnSize = CGSize(
      width: (size.width - 100 - 20) / 2,
      height: (size.width - 100 - 20) / 2
    )
    
    return VStack(spacing: 20) {
      HStack(spacing: 20) {
        buildBigNumButton(from: btns[0], size: btnSize, corners: [.topRight, .bottomLeft])
        buildBigNumButton(from: btns[1], size: btnSize, corners: [.topLeft, .bottomRight])
      }
      HStack(spacing: 20) {
        buildBigNumButton(from: btns[2], size: btnSize, corners: [.topLeft, .bottomRight])
        buildBigNumButton(from: btns[3], size: btnSize, corners: [.topRight, .bottomLeft])
      }
    }
  }
  
  func buildOpButton(from item: ButtonItem) -> some View {
    Button(action: {
      if (model.isInvalidOp) {
        model.currentOpBtnIndex = item.index
        withAnimation { attempts += 1 }
        
        player = try! AVAudioPlayer(contentsOf: errSound)
        player.play()
        feedback.notificationOccurred(.error)
      }
      else {
        model.apply(item: item)
        
        player = try! AVAudioPlayer(contentsOf: opSound)
        player.play()
      }
    }, label: {
      Text(item.title)
    })
    .frame(width: 52, height: 52)
    .buttonStyle(OpButtonStyle())
    .if(model.currentOpBtnIndex == item.index) { $0.modifier(Shake(animatableData: CGFloat(attempts))) }
    .background(
      Circle()
        .stroke(lineWidth: 4)
        .foregroundColor(.primary)
        .opacity(item.index == model.currentOpBtnIndex && !model.isInvalidOp ? 1 : 0)
    )
  }
  
  func buildOperations(from ops: [ButtonItem]) -> some View {
    return HStack {
      ForEach(ops, id: \.self) { op in
        buildOpButton(from: op)
      }
    }
  }
  
  func buildSettings(size: CGSize) -> some View {
    let btns = [
      SettingButtonItem(image: "calendar.badge.plus", text: "新游戏"),
      SettingButtonItem(image: "lightbulb.fill", text: "看答案"),
      SettingButtonItem(image: "arrow.uturn.left", text: "撤一步"),
      SettingButtonItem(image: "pencil", text: "自定义")
    ]
    
    return HStack(spacing: 40) {
      ForEach(btns.indices, id: \.self) { index in
        Button(action: {
          settingsHandler(index)
        }, label: {
          VStack {
            Image(systemName: btns[index].image)
              .font(.title3)
              .frame(width: 40, height: 36)
            
            Text(btns[index].text)
              .font(.caption)
          }
          .foregroundColor(.primary)
        })
      }
    }
//    .padding(.horizontal, 15)
    .padding(.top, 5)
    .padding(.bottom, 10)
    .frame(width: size.width - 100)
    .background(RoundedRectangle(cornerRadius: 9).fill(Color(UIColor.systemGray5)))
  }
  
  func settingsHandler(_ index: Int) {
    if index == 0 {
      model.update()
    }
    else if index == 1 {
      activeSheet = .answer
      ifPresentSheet = true
    }
    else if index == 2 {
      model.revokeOperation()
    }
    else if index == 3 {
      activeSheet = .customGame
      ifPresentSheet = true
    }
  }
}

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}
